package com.sidom.movieIndexer.matcher;

import java.lang.reflect.Type;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.Factory;
import org.hamcrest.TypeSafeMatcher;

import com.sidom.movieIndexer.domain.Movie;
import com.sidom.movieIndexer.domain.file.MovieFile;

/**
 * Custom {@link Matcher} that only compares if the {@link MovieFile}s of a {@link Movie} are the same.
 * @author Siebe
 */
public class MovieFileMatcher extends TypeSafeMatcher<Movie> {
    /**
     * The expected {@link Movie}
     */
	private final Movie expectedMovie;
	/**
     * The last {@link Movie} that was used for comparison.
     */
	private Movie lasMovie = null;

	/**
	 * Constructor.
	 * @param expectedMovie the expected {@link Movie}.
	 */
    public MovieFileMatcher(Movie expectedMovie) {
        this.expectedMovie = expectedMovie;
    }

    /**
     * Do a save match.
     * @param movie The {@link Movie} to compare to.
     */
    public boolean matchesSafely(Movie movie) {
    	lasMovie = movie;
    	if(movie==expectedMovie){
			return true;
		}
    	if(movie==null && expectedMovie==null){
			return true;
		}
    	if(movie==null){
			return false;
		}
    	if(expectedMovie==null){
			return false;
		}
    	if(movie.getMovieFile()==null && expectedMovie.getMovieFile()==null){
			return true;
		}
    	if(movie.getMovieFile()==null){
			return false;
		}
    	if(expectedMovie.getMovieFile()==null){
			return false;
		}
    	//Equals method of MovieFile isn't used because we don't want to do equal comparison on cleanedFileName.
        return new EqualsBuilder()
        					.append(movie.getMovieFile().getFileNameWithoutExtension(), expectedMovie.getMovieFile().getFileNameWithoutExtension())
        					.append(movie.getMovieFile().getFile(), expectedMovie.getMovieFile().getFile())
        					.append(movie.getMovieFile().getParentPath(), expectedMovie.getMovieFile().getParentPath()).isEquals();
    }
    
    /**
     * The factory.
     * @param <T> Should be a {@link Type}.
     * @param expectedMovie The expected {@link Movie}.
     * @return a {@link Movie} {@link Matcher}.
     */
    @Factory
    public static <T> Matcher<Movie> hasMovieFile(Movie expectedMovie) {
        return new MovieFileMatcher(expectedMovie);
    }
    
    /**
     * @param description The description if failed.
     */
	@Override
	public void describeTo(Description description) {
		description.appendText("Expected movie file: ");
		description.appendText(expectedMovie.getMovieFile().toString());
		description.appendText("but was movie file: ");
		description.appendText(lasMovie.getMovieFile().toString());
	}
}
